package com.mcdao.wssdemo.server;

import java.io.File;
import java.net.URI;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;

public class WssServer {
	private static Logger logger = LogManager.getLogger(WssServer.class);

	public static void main(String[] args) throws Exception {
		WssServer server = new WssServer();
		server.WssServerInit("wss://127.0.0.1:8443/");
	}

	public void WssServerInit(String socketUrl) throws Exception {
		URI uri = new URI(socketUrl);
		final String host = uri.getHost() == null ? "127.0.0.1" : uri.getHost();
		final int port = uri.getPort();
		File certificate = new File("C:/Users/Kevin/ssl/server.crt"); // 证书
		File privateKey = new File("C:/Users/Kevin/ssl/server_pkcs8.pem"); // 私钥
		SslContext sslCtx = SslContextBuilder.forServer(certificate, privateKey).build();
		// 此方法是Netty提供的临时生成证书测试用, 不安全, 不推荐使用
		// SelfSignedCertificate ssc = new SelfSignedCertificate();
		// SslContext sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();

		EventLoopGroup bossGroup = new NioEventLoopGroup();
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			ServerBootstrap bootstrap = new ServerBootstrap();
			bootstrap.group(bossGroup, workerGroup);
			bootstrap.channel(NioServerSocketChannel.class);
			bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel sc) throws Exception {
					ChannelPipeline pipeline = sc.pipeline();
					pipeline.addLast("ssl", sslCtx.newHandler(sc.alloc()));
					pipeline.addLast(new HttpServerCodec());
					pipeline.addLast("encoder", new StringEncoder());
					pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
					pipeline.addLast(new WebSocketServerCompressionHandler());
					pipeline.addLast(new WebSocketServerProtocolHandler("/", null, true));
					pipeline.addLast("decoder", new StringDecoder());
					pipeline.addLast(new WssServerHandler());
				}
			});

			ChannelFuture cf = bootstrap.bind(host, port).sync();
			logger.info("==========================================================");
			logger.info("============WssNetty Server Successfully Started============");
			logger.info("==========================================================");
			cf.channel().closeFuture().sync();
		} catch (Exception e) {
			logger.error("=================================================");
			logger.error("============WssNetty Server Bind Host/Port Failed============");
			logger.error("=================================================");
			e.printStackTrace();
		} finally {
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
	}
}
